// 使用 async_hooks 保证在一个事物下拿到的 connection 是同一个，并且自动提交
import asyncHooks from "node:async_hooks"
import { ConnectionInfo } from "./ConnectionInfo"
import { TransactionManager } from "./TransactionManager"

const AsyncLocalStorage = asyncHooks.AsyncLocalStorage
const asyncLocalStorage = new AsyncLocalStorage()

export class TransactionContext {
  // 单例
  private constructor() {
  }

  private static instance: TransactionContext

  public static getInstance(): TransactionContext {
    if (!TransactionContext.instance) {
      TransactionContext.instance = new TransactionContext()
    }

    return TransactionContext.instance
  }

  private transactionManager: TransactionManager

  public setTransactionManager(transactionManager: TransactionManager) {
    this.transactionManager = transactionManager
  }

  // beginTransaction
  async runInNewHookContext(callback) {
    // 事物开始，连接必须从 DataSource 里面获取新的
    const connection = await this.transactionManager.getDatasource().getConnection()
    try {
      // 返回的值是 callback 的返回值
      return await asyncLocalStorage.run(new ConnectionInfo(connection, true, true), callback)
    } catch (e) {
      // 发生任何异常都回滚
      await connection.rollback()
      console.error(e)
      return null
    } finally {
      connection.release()
      asyncLocalStorage.disable()
      // console.log('runInNewHookContext disable & release')
    }
  }

  getConnectionInfo(): ConnectionInfo | null {
    return asyncLocalStorage.getStore() as ConnectionInfo
  }
}
